package net.tavion.angelboot.gateway.jwt;

import io.jsonwebtoken.*;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

/**
 * @author : tavion
 * @date : 2019/4/19 11:33
 **/
@Component
public class JwtUtil {

   // private static final String JWT_ID = UUID.randomUUID().toString();

    private static final String ISSUER = "net.fz.angelBoot";

    public static final String ROL = "ROL";
    public static final String REQUESTCHANNEL="requestChannel";

    public static final String TOKEN_PREFIX = "Bearer ";

    @Resource
    private JwtProperties jwtProperties;

    /**
     * Generates an encrypted key from a string
     *
     * @return
     */
    private SecretKey generalKey() {
        String jwtSecret = jwtProperties.getSecret();
        // not found, give default
        if(StringUtils.isBlank(jwtSecret)){
            jwtSecret = "secret_key";
        }
        // Local password decoding
        byte[] encodedKey = Base64.decodeBase64(jwtSecret);
        // Construct a key from a given byte array using the AES encryption algorithm
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

        return key;
    }

    /**
     * create jwt
     * @param subject userId or userName
     * @param claims business data
     * @return jwt token
     * @throws Exception
     */
    public String createJWT(String subject, Map<String, Object> claims) {

        // The signature algorithm used when specifying the signature, namely the header section, has been encapsulated by JJWT.
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        //Time to generate JWT
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        // Generate the signature using the secret key secret, remember that this secret key can not be exposed oh.It is the private key of your server and should not be exposed in any scenario.
        // Once the client is aware of this secret, it means that the client can issue the JWT itself.
        SecretKey key = generalKey();

        // This is the payload for adding various standard and private declarations
        // New JwtBuilder, set the body of JWT
        JwtBuilder builder = Jwts.builder()
                // If you have a private declaration, be sure to set the self-created private declaration, which is the claim value for the builder. Once written after the standard declaration is assigned, it overrides the standard declaration
                .setClaims(claims)
                // Set jti(JWT ID) : is the unique identity of JWT, which can be set to a non-repeating value according to business needs, mainly used as a one-time token to avoid replay attacks.
                .setId(UUID.randomUUID().toString())
                // iat: The issuance of jwt time
                .setIssuedAt(now)
                // issuer：Issued by JWT people
                .setIssuer(ISSUER)
                // sub(Subject)：The body representing this JWT, which is its owner, is a json-formatted string that can hold something like userid, roldid, and so on, as the unique flag of what user it is.
                .setSubject(subject)
                // Sets the signature algorithm used by the signature and the secret key used by the signature
                .signWith(signatureAlgorithm, key);

        // Set expiration time
//        if (expiredTime >= 0) {
//            long expMillis = nowMillis + expiredTime;
//            Date exp = new Date(expMillis);
//            builder.setExpiration(exp);
//        }
        return builder.compact();
    }

    /**
     * decode jwt
     *
     * @param jwt
     * @return
     * @throws SignatureException
     */
    public Claims parseJWT(String jwt) throws SignatureException {
        //The signed secret key is exactly the same as that of the generated signature
        SecretKey key = generalKey();
        //get DefaultJwtParser
        Claims claims = Jwts.parser()
                //Sets the secret key for the signature
                .setSigningKey(key)
                //Set the JWT to be parsed
                .parseClaimsJws(jwt).getBody();
        return claims;
    }

}
